home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / ELVIS / SYSTEM.C < prev    next >
C/C++ Source or Header  |  1992-10-01  |  9KB  |  439 lines

  1. /* system.c  -- UNIX version */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains a new version of the system() function and related stuff.
  12.  *
  13.  * Entry points are:
  14.  *    system(cmd)    - run a single shell command
  15.  *    wildcard(names)    - expand wildcard characters in filanames
  16.  *    filter(m,n,cmd)    - run text lines through a filter program
  17.  *
  18.  * This is probably the single least portable file in the program.  The code
  19.  * shown here should work correctly if it links at all; it will work on UNIX
  20.  * and any O.S./Compiler combination which adheres to UNIX forking conventions.
  21.  */
  22.  
  23. #include "config.h"
  24. #include "vi.h"
  25. #include <signal.h>
  26. extern char    **environ;
  27.  
  28. #if ANY_UNIX || DF_POSIX
  29.  
  30. /* This is a new version of the system() function.  The only difference
  31.  * between this one and the library one is: this one uses the o_shell option.
  32.  */
  33. int system(cmd)
  34.     char    *cmd;    /* a command to run */
  35. {
  36.     int    status;    /* exit status of the command */
  37.  
  38.     /* warn the user if the file hasn't been saved yet */
  39.     if (*o_warn && tstflag(file, MODIFIED))
  40.     {
  41.         if (mode == MODE_VI)
  42.         {
  43.             mode = MODE_COLON;
  44.         }
  45.         msg("Warning: \"%s\" has been modified but not yet saved", origname);
  46.     }
  47.  
  48.     signal(SIGINT, SIG_IGN);
  49.     switch (fork())
  50.     {
  51.       case -1:                        /* error */
  52.         msg("fork() failed");
  53.         status = -1;
  54.         break;
  55.  
  56.       case 0:                        /* child */
  57.         /* for the child, close all files except stdin/out/err */
  58.         for (status = 3; status < 60 && (close(status), errno != EINVAL); status++)
  59.         {
  60.         }
  61.  
  62.         signal(SIGINT, SIG_DFL);
  63.         if (cmd == o_shell)
  64.         {
  65.             execle(o_shell, o_shell, (char *)0, environ);
  66.         }
  67.         else
  68.         {
  69.             execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
  70.         }
  71.         msg("execle(\"%s\", ...) failed", o_shell);
  72.         exit(1); /* if we get here, the exec failed */
  73.  
  74.       default:                        /* parent */
  75.         wait(&status);
  76.         signal(SIGINT, trapint);
  77.     }
  78.  
  79.     return status;
  80. }
  81.  
  82. /* This private function opens a pipe from a filter.  It is similar to the
  83.  * system() function above, and to popen(cmd, "r").
  84.  */
  85. static int rpipe(cmd, in)
  86.     char    *cmd;    /* the filter command to use */
  87.     int    in;    /* the fd to use for stdin */
  88. {
  89.     int    r0w1[2];/* the pipe fd's */
  90.  
  91.     /* make the pipe */
  92.     if (pipe(r0w1) < 0)
  93.     {
  94.         return -1;    /* pipe failed */
  95.     }
  96.  
  97.     /* The parent process (elvis) ignores signals while the filter runs.
  98.      * The child (the filter program) will reset this, so that it can
  99.      * catch the signal.
  100.      */
  101.     signal(SIGINT, SIG_IGN);
  102.  
  103.     switch (fork())
  104.     {
  105.       case -1:                        /* error */
  106.         return -1;
  107.  
  108.       case 0:                        /* child */
  109.         /* close the "read" end of the pipe */
  110.         close(r0w1[0]);
  111.  
  112.         /* redirect stdout to go to the "write" end of the pipe */
  113.         close(1);
  114.         dup(r0w1[1]);
  115.         close(2);
  116.         dup(r0w1[1]);
  117.         close(r0w1[1]);
  118.  
  119.         /* redirect stdin */
  120.         if (in != 0)
  121.         {
  122.             close(0);
  123.             dup(in);
  124.             close(in);
  125.         }
  126.  
  127.         /* the filter should accept SIGINT signals */
  128.         signal(SIGINT, SIG_DFL);
  129.  
  130.         /* exec the shell to run the command */
  131.         execle(o_shell, o_shell, "-c", cmd, (char *)0, environ);
  132.         exit(1); /* if we get here, exec failed */
  133.  
  134.       default:                        /* parent */
  135.         /* close the "write" end of the pipe */    
  136.         close(r0w1[1]);
  137.  
  138.         return r0w1[0];
  139.     }
  140. }
  141.  
  142. #endif /* non-DOS */
  143.  
  144. #if OSK
  145.  
  146. /* This private function opens a pipe from a filter.  It is similar to the
  147.  * system() function above, and to popen(cmd, "r").
  148.  */
  149. static int rpipe(cmd, in)
  150.     char    *cmd;    /* the filter command to use */
  151.     int    in;    /* the fd to use for stdin */
  152. {
  153.  
  154.     char **argblk;
  155.     char *p, *buffer, *command;
  156.     int stdinp, stdoutp;
  157.     unsigned addstack = 0;
  158.     int words, len, loop = 1;
  159.     int fp, pipe_pid;
  160.     extern int os9forkc();
  161.     extern char *index();
  162.  
  163.     command = cmd;
  164.     words = 0;
  165.     if ((buffer = (char*) malloc(strlen(cmd))) == (char*) 0)
  166.         return 0;
  167.  
  168.     do {
  169.         if (!(p = index(command, ' '))) {
  170.             loop--;
  171.             len = strlen(command);
  172.         }
  173.         else
  174.             len = p - command;
  175.         words++;    
  176.         while (command[len] && command[len] == ' ')
  177.             len++;
  178.         if (!command[len])
  179.             break;
  180.         command = command + len;
  181.     }    
  182.     while (loop);
  183.     if ((argblk = (char **)malloc((words+1) * sizeof(char*))) == (char **)0)
  184.         return 0;
  185.     command = cmd;
  186.     words = 0;
  187.     do {
  188.         if (!(p = index(command, ' '))) {
  189.             loop--;
  190.             len = strlen(command);
  191.         }
  192.         else
  193.             len = p - command;
  194.         strncpy(buffer, command, len);
  195.         argblk[words++] = buffer;
  196.         buffer += len;
  197.         *buffer++ = '\0';
  198.         while (command[len] && command[len] == ' ')
  199.             len++;
  200.         if (!command[len])
  201.             break;
  202.         command = command + len;
  203.     } while (loop);
  204.     if (argblk[words - 1][0] == '#') 
  205.         addstack = 1024 * atoi(&argblk[--words][1]);
  206.     argblk[words] = 0;
  207.  
  208.     stdoutp = dup(1);
  209.     close(1);               /* close stdout */
  210.     if ((fp = open("/pipe",S_IREAD)) < 0) {
  211.         dup(stdoutp);
  212.         close(stdoutp);
  213.         return 0;
  214.     }
  215.     if (in != 0) {
  216.         stdinp = dup(0);
  217.         close(0);
  218.         dup(in);
  219.         close(in);
  220.     }
  221.     pipe_pid = os9exec(os9forkc,argblk[0],argblk,environ,addstack,0,3);
  222.     if (pipe_pid == -1) {
  223.         fclose(fp);
  224.         dup(stdoutp);
  225.         close(stdoutp);
  226.         if (in != 0) {
  227.             close(0);
  228.             dup(stdinp);
  229.         }
  230.         return 0;
  231.     }
  232.     fp = (short)dup(1);     /* save pipe */
  233.     close(1);               /* get rid of the pipe */
  234.     dup(stdoutp);           /* restore old stdout */
  235.     close(stdoutp);         /* close path to stdout copy */
  236.     if (in != 0) {
  237.         close(0);
  238.         dup(stdinp);
  239.     }
  240.     return fp;
  241. }    
  242. #endif
  243.  
  244. #if ANY_UNIX || OSK || DF_POSIX
  245.  
  246. /* This function closes the pipe opened by rpipe(), and returns 0 for success */
  247. static int rpclose(fd)
  248.     int    fd;
  249. {
  250.     int    status;
  251.  
  252.     close(fd);
  253.     wait(&status);
  254.     signal(SIGINT, trapint);
  255.     return status;
  256. }
  257.  
  258. #endif /* non-DOS */
  259.  
  260. /* This function expands wildcards in a filename or filenames.  It does this
  261.  * by running the "echo" command on the filenames via the shell; it is assumed
  262.  * that the shell will expand the names for you.  If for any reason it can't
  263.  * run echo, then it returns the names unmodified.
  264.  */
  265.  
  266. #if MSDOS || TOS
  267. #define    PROG    "wildcard "
  268. #define    PROGLEN    9
  269. #include <string.h>
  270. #else
  271. #define    PROG    "echo "
  272. #define    PROGLEN    5
  273. #endif
  274.  
  275. char *wildcard(names)
  276.     char    *names;
  277. {
  278.     int    i, j, fd;
  279.     REG char *s, *d;
  280.  
  281.  
  282.     /* build the echo command */
  283.     if (names != tmpblk.c)
  284.     {
  285.         /* the names aren't in tmpblk.c, so we can do it the easy way */
  286.         strcpy(tmpblk.c, PROG);
  287.         strcat(tmpblk.c, names);
  288.     }
  289.     else
  290.     {
  291.         /* the names are already in tmpblk.c, so shift them to make
  292.          * room for the word "echo "
  293.          */
  294.         for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; )
  295.         {
  296.             *--d = *--s;
  297.         }
  298.         strncpy(names, PROG, PROGLEN);
  299.     }
  300.  
  301.     /* run the command & read the resulting names */
  302.     fd = rpipe(tmpblk.c, 0);
  303.     if (fd < 0) return names;
  304.     i = 0;
  305.     do
  306.     {
  307.         j = tread(fd, tmpblk.c + i, BLKSIZE - i);
  308.         i += j;
  309.     } while (j > 0);
  310.  
  311.     /* successful? */
  312.     if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0)
  313.     {
  314.         tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */
  315.         return tmpblk.c;
  316.     }
  317.     else
  318.     {
  319.         return names;
  320.     }
  321. }
  322.  
  323. /* This function runs a range of lines through a filter program, and replaces
  324.  * the original text with the filtered version.  As a special case, if "to"
  325.  * is MARK_UNSET, then it runs the filter program with stdin coming from
  326.  * /dev/null, and inserts any output lines.
  327.  */
  328. int filter(from, to, cmd)
  329.     MARK    from, to;    /* the range of lines to filter */
  330.     char    *cmd;        /* the filter command */
  331. {
  332.     int    scratch;    /* fd of the scratch file */
  333.     int    fd;        /* fd of the pipe from the filter */
  334.     char    scrout[50];    /* name of the scratch out file */
  335.     MARK    new;        /* place where new text should go */
  336.     int    i;
  337.  
  338.     /* write the lines (if specified) to a temp file */
  339.     if (to)
  340.     {
  341.         /* we have lines */
  342. #if MSDOS || TOS
  343.         strcpy(scrout, o_directory);
  344.         if ((i=strlen(scrout)) && strchr("\\/:", scrout[i-1]))
  345.             scrout[i++]=SLASH;
  346.         strcpy(scrout+i, SCRATCHOUT+3);
  347. #else
  348.         sprintf(scrout, SCRATCHOUT, o_directory);
  349. #endif
  350. #ifdef DF_POSIX
  351.         // BUG!BUG tmpnam(scrout);
  352. #else
  353.         mktemp(scrout);
  354. #endif
  355.         cmd_write(from, to, CMD_BANG, 0, scrout);
  356.  
  357.         /* use those lines as stdin */
  358.         scratch = open(scrout, O_RDONLY);
  359.         if (scratch < 0)
  360.         {
  361.             unlink(scrout);
  362.             return -1;
  363.         }
  364.     }
  365.     else
  366.     {
  367.         scratch = 0;
  368.     }
  369.  
  370.     /* start the filter program */
  371.     fd = rpipe(cmd, scratch);
  372.     if (fd < 0)
  373.     {
  374.         if (to)
  375.         {
  376.             close(scratch);
  377.             unlink(scrout);
  378.         }
  379.         return -1;
  380.     }
  381.  
  382.     ChangeText
  383.     {
  384.         /* adjust MARKs for whole lines, and set "new" */
  385.         from &= ~(BLKSIZE - 1);
  386.         if (to)
  387.         {
  388.             to &= ~(BLKSIZE - 1);
  389.             to += BLKSIZE;
  390.             new = to;
  391.         }
  392.         else
  393.         {
  394.             new = from + BLKSIZE;
  395.         }
  396.  
  397.         /* repeatedly read in new text and add it */
  398.         while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
  399.         {
  400.             tmpblk.c[i] = '\0';
  401.             add(new, tmpblk.c);
  402.             for (i = 0; tmpblk.c[i]; i++)
  403.             {
  404.                 if (tmpblk.c[i] == '\n')
  405.                 {
  406.                     new = (new & ~(BLKSIZE - 1)) + BLKSIZE;
  407.                 }
  408.                 else
  409.                 {
  410.                     new++;
  411.                 }
  412.             }
  413.         }
  414.     }
  415.  
  416.     /* delete old text, if any */
  417.     if (to)
  418.     {
  419.         delete(from, to);
  420.     }
  421.  
  422.     /* Reporting... */
  423.     rptlabel = "more";
  424.     if (rptlines < 0)
  425.     {
  426.         rptlines = -rptlines;
  427.         rptlabel = "less";
  428.     }
  429.  
  430.     /* cleanup */
  431.     rpclose(fd);
  432.     if (to)
  433.     {
  434.         close(scratch);
  435.         unlink(scrout);
  436.     }
  437.     return 0;
  438. }
  439.